Skip to content

feat(diff): register kb.diff at all four kb.* surface sites#344

Merged
plind-junior merged 1 commit into
vouchdev:testfrom
jsdevninja:feat/327-kb-diff-parity
Jul 6, 2026
Merged

feat(diff): register kb.diff at all four kb.* surface sites#344
plind-junior merged 1 commit into
vouchdev:testfrom
jsdevninja:feat/327-kb-diff-parity

Conversation

@jsdevninja

@jsdevninja jsdevninja commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

summary

closes #327. vouch diff <id-old> <id-new> shipped CLI-only in 0.1.0
(#86) — an explicit non-goal at the time ("MCP/JSONL parity ... kb.*
surface unchanged"). that left kb.diff as the only read method
skipping the four-site registration convention (CLAUDE.md §"When you
add a new kb.* method"), so agents talking MCP or JSONL had no way to
fetch a revision diff.

  • registers kb.diff at the remaining three sites: kb_diff MCP tool
    in server.py, _h_diff/kb.diff in jsonl_server.py, and
    capabilities.METHODS — placed next to kb_read_claim/kb_read_page
    with the same unrestricted-read posture (no ViewerContext scope
    filtering, matching the other by-id reads).
  • new_id is now optional for a claim: diff_artifacts and the CLI
    both resolve it from superseded_by when omitted, erroring clearly
    when there's no successor. pages still require an explicit new_id
    (no successor pointer on the Page model).
  • updates the original design doc
    (docs/superpowers/specs/2026-05-25-vouch-diff-design.md) to record
    the superseded "CLI-only" decision and the new surface.
  • diff logic still lives entirely in src/vouch/diff.py; storage.py
    is untouched.

read-only throughout — no proposal emitted, no artifact or audit event
written (asserted directly in tests/test_diff.py).

test plan

  • pytest tests/test_diff.py tests/test_capabilities.py tests/test_provenance.py -q — 66 passed (20 in test_diff.py,
    including the new kb.diff RPC-surface, omitted-new_id, and
    read-only tests)
  • mypy src — clean (two pre-existing, unrelated sandbox.py
    errors on this Windows checkout, confirmed present on main too)
  • ruff check src tests — clean
  • confirmed kb.diff registered at all four sites; test_capabilities
    (capabilities.METHODS == HANDLERS.keys()) stays green

Summary by CodeRabbit

  • New Features

    • Added vouch diff support across CLI and API surfaces via a new kb.diff tool/handler (MCP and JSONL).
    • The newer revision (new_id) is now optional for superseded claims, enabling automatic resolution.
  • Bug Fixes

    • Improved diff error handling: claims with no successor and page diffs without an explicit new_id now fail with clear, explicit errors.
    • Diff operations remain read-only and do not generate audit events or proposals.
  • Documentation

    • Updated the vouch diff design and changelog to reflect MCP/JSONL parity and the revised resolution rules.

@github-actions github-actions Bot added docs documentation, specs, examples, and repo guidance cli command line interface mcp mcp, jsonl, and http surfaces sync sync, vault mirror, and diff flows tests tests and fixtures size: S 50-199 changed non-doc lines labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

diff_artifacts now resolves an omitted new_id through superseded_by for claims, and kb.diff is exposed through the CLI, MCP server, JSONL handler, capabilities list, tests, and documentation.

Changes

kb.diff optional new_id and MCP/JSONL parity

Layer / File(s) Summary
diff_artifacts resolves optional successor
src/vouch/diff.py
diff_artifacts accepts new_id=None, derives the successor from superseded_by when needed, and raises DiffError for pages or unsuperseded claims.
CLI and kb.diff entry points
src/vouch/cli.py, src/vouch/server.py, src/vouch/jsonl_server.py, src/vouch/capabilities.py
vouch diff accepts an optional new_id; kb_diff and _h_diff call diff_artifacts, JSONL dispatch registers kb.diff, and the capability list advertises it.
Tests, changelog, and design docs
tests/test_diff.py, CHANGELOG.md, docs/superpowers/specs/2026-05-25-vouch-diff-design.md
Tests cover omitted-new_id resolution, error paths, read-only behavior, CLI output, and kb.diff RPC responses; docs record the updated surface and semantics.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as cli.py
  participant MCP as server.py
  participant JSONL as jsonl_server.py
  participant Diff as diff.py
  participant Store as KBStore

  CLI->>Diff: diff_artifacts(store, old_id, new_id?)
  MCP->>Diff: diff_artifacts(_store(), old_id, new_id?)
  JSONL->>Diff: diff_artifacts(_store(), old_id, new_id?)
  Diff->>Store: load old artifact
  Diff->>Store: read superseded_by when new_id omitted
  Diff-->>CLI: ArtifactDiff / DiffError
  Diff-->>MCP: ArtifactDiff
  Diff-->>JSONL: ArtifactDiff
Loading

Possibly related PRs

  • vouchdev/vouch#84: Both PRs modify the vouch diff CLI wiring and new_id handling.
  • vouchdev/vouch#86: Both PRs evolve src/vouch/diff.py and vouch diff behavior around artifact diffs.
  • vouchdev/vouch#111: The earlier diff implementation is extended here with optional successor resolution and kb.diff surfaces.

Suggested reviewers: plind-junior

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR covers diff surfaces and read-only behavior, but it does not honor ViewerContext scope filtering required by #327. Apply the same visibility rules used by other read methods so kb.diff hides artifacts the caller cannot already read.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed All changes relate to exposing and testing vouch diff, plus the matching design-doc update.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: registering kb.diff across the kb.* surfaces.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/vouch/diff.py (1)

86-96: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Reuse the already-fetched claim to avoid a redundant read.

When new_id is omitted, old_id's claim is fetched here to read superseded_by, then fetched again at line 106 to build old. Since kb.diff is now also exposed via MCP/JSONL (potentially higher call volume than the CLI), reusing the object avoids an unnecessary disk read + YAML parse per call.

♻️ Proposed fix
     if new_id is None:
         if old_kind != "claim":
             raise DiffError(
                 f"{old_id} is a {old_kind}; pages have no successor pointer, "
                 "pass new_id explicitly"
             )
         old_claim = store.get_claim(old_id)
         if not old_claim.superseded_by:
             raise DiffError(f"{old_id} has not been superseded; pass new_id explicitly")
         new_id = old_claim.superseded_by
+    else:
+        old_claim = None

     new_kind = _kind_of(store, new_id)
     if new_kind is None:
         raise DiffError(f"unknown artifact: {new_id}")
     if old_kind != new_kind:
         raise DiffError(f"cannot diff {old_kind} against {new_kind}")

     old: Claim | Page
     new: Claim | Page
     if old_kind == "claim":
-        old, new = store.get_claim(old_id), store.get_claim(new_id)
+        old, new = old_claim or store.get_claim(old_id), store.get_claim(new_id)
         fields, text_field = _CLAIM_FIELDS, _CLAIM_TEXT
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/vouch/diff.py` around lines 86 - 96, The fallback path in diff logic is
doing a redundant claim read when new_id is omitted. Update the diff-building
flow around the existing store.get_claim call in the kb.diff path so the fetched
old_claim is reused later instead of fetching the same claim again when
constructing old, while keeping the superseded_by check and DiffError behavior
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/vouch/diff.py`:
- Around line 86-96: The fallback path in diff logic is doing a redundant claim
read when new_id is omitted. Update the diff-building flow around the existing
store.get_claim call in the kb.diff path so the fetched old_claim is reused
later instead of fetching the same claim again when constructing old, while
keeping the superseded_by check and DiffError behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cdc8645d-68d0-463b-9f75-745ef1b4e124

📥 Commits

Reviewing files that changed from the base of the PR and between 5f58c69 and 9b1e733.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • docs/superpowers/specs/2026-05-25-vouch-diff-design.md
  • src/vouch/capabilities.py
  • src/vouch/cli.py
  • src/vouch/diff.py
  • src/vouch/jsonl_server.py
  • src/vouch/server.py
  • tests/test_diff.py

vouch diff shipped CLI-only in 0.1.0, an explicit non-goal at the time
("MCP/JSONL parity ... kb.* surface unchanged"). that leaves it the only
read method skipping the four-site registration convention documented in
CLAUDE.md, so agents talking MCP/JSONL have no way to fetch a revision
diff. adds the kb_diff MCP tool, the kb.diff JSONL handler, and the
capabilities.METHODS entry, next to the other by-id read tools
(kb_read_claim/kb_read_page) with the same unrestricted-read posture.

also makes new_id optional for a superseded claim: diff_artifacts and
the CLI both resolve it from superseded_by when omitted, erroring
clearly when there's no successor (pages still require an explicit
new_id — they have no successor pointer). closes vouchdev#327.
@jsdevninja jsdevninja force-pushed the feat/327-kb-diff-parity branch from 9b1e733 to f2b554c Compare July 6, 2026 06:01
@plind-junior plind-junior changed the base branch from main to test July 6, 2026 08:34
@plind-junior

Copy link
Copy Markdown
Collaborator

I'm considering to deprecate code diff comparison feature as it takes much effort to run LLMs. Or potentially, we could add it in v2.0.0
I will merge it for now but do not focus on this feature until I create a new ticket

@plind-junior plind-junior merged commit 2982a6c into vouchdev:test Jul 6, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli command line interface docs documentation, specs, examples, and repo guidance mcp mcp, jsonl, and http surfaces size: S 50-199 changed non-doc lines sync sync, vault mirror, and diff flows tests tests and fixtures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: vouch diff <id-old> <id-new> — revision diff for claims and pages

2 participants